﻿using System;

using System.Collections;
using System.Collections.Generic;

using System.Data;
using System.Data.Common;

using System.Linq;

using System.Net.Mail;

using System.Runtime.Serialization;

using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;

using Microsoft.Practices.EnterpriseLibrary;
using Microsoft.Practices.EnterpriseLibrary.Common;
using Microsoft.Practices.EnterpriseLibrary.Data;

using nms.gaming.progressive.model;
using nms.gaming.model;
using nms.gaming.webservice.RandomNumberServiceReference;

namespace nms.gaming.webservice
{
    /// <summary>
    /// </summary>
    [ServiceBehavior(IncludeExceptionDetailInFaults = true)]
    [JavascriptCallbackBehavior(UrlParameterName = "$callback")]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class ProgressiveJackpot : IProgressiveJackpotService
    {

        /// <summary>
        /// </summary>
        /// <param name="host"></param>
        /// <param name="game"></param>
        /// <param name="symbol"></param>
        public GamingEvent Discover(string host, string game, string symbol)
        {
            /// --
            GamingEvent _response = new GamingEvent()
            {
                Id      = Guid.NewGuid().ToString(),
                Host    = host,
                Game    = game,
            };

            GamingAction _action = new GamingAction()
            {
                Id      = Guid.NewGuid().ToString( ),
                Name    = "Jackpot Discovery Reply" ,
                Type    = "nms.gaming.jackpotfunds"  ,

                DateTime            = DateTime.Now,
                DateTimeString = DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ssZ")
            };

            /// --
            Database _db = DatabaseFactory.CreateDatabase();
            IRowMapper<JackpotFund> rowMapper = MapBuilder<JackpotFund>
                .MapAllProperties()
                .Map(b => b.Id).ToColumn("ID")
                .Map(b => b.Name).ToColumn("NAME")
                .Map(b => b.Value).WithFunc(
                    b => new Currency()
                    {
                        Symbol = b.GetString(b.GetOrdinal("SYMBOL")),
                        Volume = b.GetDecimal(b.GetOrdinal("SECURED_VOLUME"))
                    }
                 )
                 .Map(b => b.Estimated).WithFunc(
                    b => new Currency()
                    {
                        Symbol = b.GetString(b.GetOrdinal("SYMBOL")),
                        Volume = b.GetDecimal(b.GetOrdinal("ESTIMATED_VOLUME"))
                    }
                 )
                .Map(b => b.Growth).WithFunc(
                    b => new JackpotFundGrowth()
                    {
                        Rate = new TimeInterval()
                        {
                            Unit = TimeUnit.Second,
                            Value = b.GetInt32(b.GetOrdinal("GROWTH_RATE_INTERVAL"))
                        },

                        Value = new Currency()
                        {
                            Symbol = b.GetString(b.GetOrdinal("SYMBOL")),
                            Volume = b.GetDecimal(b.GetOrdinal("GROWTH_RATE_VOLUME"))
                        }
                    }
                )
                .Map(b => b.DateTime).WithFunc
                (
                    b => DateTime.Now
                )
                .Map(b => b.DateTimeString).WithFunc
                (
                    b => DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ssZ")
                )
                .Build(); 
            
            /// -- the stored procedure should compute the jackpot value based
            /// -- on the last know exchange rate and the transactions listed for
            /// -- the specified jackpot
            IEnumerable<JackpotFund> _jackpotFunds = _db.ExecuteSprocAccessor<JackpotFund>("sp_JackpotDiscover_v2", rowMapper, host, game, symbol);
            _action.data = (object) new JackpotFunds() { items = _jackpotFunds.ToList<JackpotFund>() }; 
            _response.Actions.Add(_action);

            
            /// --
            return _response;

        }

        /// <summary>
        /// </summary>
        /// <param name="host"></param>
        /// <param name="game"></param>
        /// <param name="symbol"></param>
        /// <returns></returns>
        public GamingEvent DiscoverJSON(string host, string game, string symbol)
        { return Discover(host, game, symbol); }

        /// <summary>
        /// </summary>
        /// <param name="host"></param>
        /// <param name="game"></param>
        /// <param name="symbol"></param>
        /// <returns></returns>
        public GamingEvent DiscoverJSON_EXPLICIT(string host, string game, string symbol)
        { return Discover(host, game, symbol); }

        /// <summary>
        /// </summary>
        public GamingEvent Play(string host, string game, string symbol, string volume)
        {
            /// --
            decimal _volume;

            /// -- perform validation of parameters
            if (!decimal.TryParse(volume, out _volume))
            { }


            /// -- 
            GamingEvent _response = new GamingEvent()
            {
                Id = Guid.NewGuid().ToString(),
                Host = host,
                Game = game
            };

            /// -- 
            Database _db = DatabaseFactory.CreateDatabase();
            using (DbConnection _dbConn = _db.CreateConnection())
            {
                /// -- open database connection
                _dbConn.Open();
                
                #region Deposit and Play for the Progressive Jackpot(s)
                /// --
                try
                {
                    /// -- Deposit and Play Transaction
                    using (DbTransaction _dbTrans = _dbConn.BeginTransaction())
                    {
                        try
                        {
                            /// -- map the returned data from the called stored procedure (below)
                            /// -- into a list of JackpotPlay entity, which holds the details about
                            /// -- the progressive jackpot odds and weather the progressive jackpot
                            /// -- group is exclusive etc.
                            IRowMapper<JackpotPlay> rowMapper = MapBuilder<JackpotPlay>
                                .MapAllProperties()
                                .Map(b => b.JackpotPlayID).ToColumn("PK_JACKPOT_PLAY_ID")
                                .Map(b => b.DepositID).ToColumn("FK_JACKPOT_DEPOSIT_ID")
                                .Map(b => b.JackpotID).ToColumn("FK_JACKPOT_ID")                       
                                .Map(b => b.JackpotName).ToColumn("JACKPOT_NAME")
                                .Map(b => b.Lower).ToColumn("LOWER")
                                .Map(b => b.Upper).ToColumn("UPPER")
                                .Map(b => b.IsExclusive).ToColumn("IS_EXCLUSIVE")
                            .Build();

                            /// -- the stored procedure will record the deposit details and should
                            /// -- return a list of progressive jackpots that can be played out for
                            /// -- the given deposit; the list may be empty if a deposit is not 
                            /// -- configured to play a progressive jackpot; the stored procedure
                            /// -- will throw an exception if the game/host/symbol is not supported.
                            IEnumerable<JackpotPlay> _jackpotPlays = _db.ExecuteSprocAccessor<JackpotPlay>("sp_JackpotDepositAndPlay", rowMapper, host, game, symbol, volume);

                            #region playout the progressive jackpot
                            using (RandomNumberServiceClient srv = new RandomNumberServiceClient())
                            {
                                /// --
                                foreach (JackpotPlay _jackpotPlay in _jackpotPlays)
                                {

                                    /// -- if exclusive then call the random number generator and determine
                                    /// -- if the number returned hits a range for any jackpot in the jackpot
                                    /// -- group?
                                    if (_jackpotPlay.IsExclusive)
                                    {
                                        /// -- call random number generator for each jackpot group
                                        /// -- that is returned from the stored procedure sp_JackpotPlay
                                        rng.model.RandomNumberSet[] _primary = srv.Generate(host, game, _jackpotPlay.Lower, _jackpotPlay.Upper, 1, false, 1);


                                    }
                                    else /// -- otherwise
                                    {
                                        /// -- if not exclusive then call the random number generator for each
                                        /// -- jackpot in the current jackpot group, request two numbers between
                                        /// -- n:x (where n:x is the odds expressed as 1 in 100, 3 in 300,000 )
                                        /// -- and therefore n number of random numbers to generate between 1 and x
                                        /// -- and if any of these match the second single number between 1 and x
                                        /// -- we have a winner!!
                                        rng.model.RandomNumberSet[] _primary = srv.Generate(host, game, 1, _jackpotPlay.Upper, 1, false, 1);
                                        rng.model.RandomNumberSet[] _secondary = srv.Generate(host, game, 1, _jackpotPlay.Upper, _jackpotPlay.Lower, false, 1);
                                    }
                                }
                            }
                            #endregion

                            
                            /// --
                            _dbTrans.Commit( );
                        }
                        catch 
                        {
                            _dbTrans.Rollback( );      
                        }
                        finally 
                        { }                        
                    }
                }
                catch
                { }
                finally 
                { }
                #endregion

                /// -- close connection we are finished
                _dbConn.Close( );  
            }

            /// --
            return _response; 
        }

        /// <summary>
        /// </summary>
        /// <param name="host"></param>
        /// <param name="game"></param>
        /// <param name="symbol"></param>
        /// <param name="volume"></param>
        /// <returns></returns>
        public GamingEvent PlayJSON(string host, string game, string symbol, string volume)
        { return Play(host, game, symbol , volume); }

        /// <summary>
        /// </summary>
        /// <param name="host"></param>
        /// <param name="game"></param>
        /// <param name="symbol"></param>
        /// <param name="volume"></param>
        /// <returns></returns>
        public GamingEvent PlayJSON_EXPLICIT(string host, string game, string symbol, string volume)
        { return Play(host, game, symbol, volume); }

    }
}
